<!--
 * @Description: 人员/用户组选择组件
 * @Version: 2.0
 * @Autor: swc
 * @Date: 2024-07-23 09:51:08
 * @LastEditors: swc shanwenchao12138@163.com
 * @LastEditTime: 2025-09-08 20:13:29
-->

<template>
  <div class="users-select-container">
    <!-- 上下布局，比例为7:3 -->
    <Layout class="users-select-layout">
      <!-- 上半部分占70% -->
      <Content class="top-section" :style="{ height: '70%' }">
        <Row :gutter="16" class="top-row">
          <!-- 左侧人员列表，占50% -->
          <Col :span="12" class="list-col">
            <div class="list-header">
              <h3>{{ $srv.getI18nByValue('人员列表') }}</h3>
            </div>
            <div class="list-content user-list-content">
              <div v-if="users.length === 0" class="empty-tip">
                {{ $srv.getI18nByValue('暂无选择项') }}
              </div>
              <Card
                v-for="user in users"
                :key="'user-' + user.nodeCode"
                :class="[
                  'select-card',
                  'user-card',
                  user.selected ? 'selected' : ''
                ]"
                @click.native="toggleUserSelection(user)"
              >
                <div class="card-checkbox-top">
                  <Checkbox
                    :value="user.selected"
                    @on-change="checked => toggleUserSelection(user, checked)"
                  />
                </div>
                <div class="card-content">
                  <div class="card-info">
                    <div class="card-name">{{ user.data.checker.label }}</div>
                    <div class="card-userNo">{{ user.data.checker.value }}</div>
                  </div>
                </div>
              </Card>
            </div>
          </Col>

          <!-- 右侧用户组列表，占50% -->
          <Col :span="12" class="list-col">
            <div class="list-header">
              <h3>{{ $srv.getI18nByValue('用户组列表') }}</h3>
            </div>
            <div class="list-content group-list-content">
              <div v-if="userGroups.length === 0" class="empty-tip">
                {{ $srv.getI18nByValue('暂无选择项') }}
              </div>
              <Card
                v-for="group in userGroups"
                :key="'group-' + group.nodeCode"
                :class="[
                  'select-card',
                  'group-card',
                  group.selected ? 'selected' : ''
                ]"
                @click.native="toggleGroupSelection(group)"
              >
                <div class="card-checkbox-top">
                  <Checkbox
                    :value="group.selected"
                    @on-change="checked => toggleGroupSelection(group, checked)"
                  />
                </div>
                <div class="card-content">
                  <div class="card-info">
                    <div class="card-name">{{ group.data.label }}</div>
                    <div class="card-details">
                      <div class="card-description">
                        {{ getGroupDescription(group) }}
                      </div>
                    </div>
                  </div>
                </div>
                <div class="card-actions-bottom">
                  <Button
                    type="primary"
                    size="small"
                    @click.stop="handleGroupManage(group)"
                  >
                    {{ $srv.getI18nByValue('管理') }}
                  </Button>
                </div>
              </Card>
            </div>
          </Col>
        </Row>
      </Content>

      <!-- 分隔线 -->
      <Divider />

      <!-- 下半部分占30% -->
      <Content class="bottom-section" :style="{ height: '30%' }">
        <div class="selected-header">
          <h3>
            {{ $srv.getI18nByValue('已选择项') }} ({{ selectedItems.length }})
          </h3>
        </div>
        <div class="selected-content">
          <div
            v-for="item in selectedItems"
            :key="`${item.type}-${item.nodeCode}`"
            class="selected-card"
          >
            <div class="selected-info">
              <div class="selected-name">
                {{
                  item.type === 0 ? item.data.checker.label : item.data.label
                }}
              </div>
              <div class="selected-type">
                <Tag :color="item.type === 0 ? 'blue' : 'green'">
                  {{
                    item.type === 0
                      ? $srv.getI18nByValue('人员')
                      : $srv.getI18nByValue('用户组')
                  }}
                </Tag>
              </div>
            </div>
          </div>
          <div v-if="selectedItems.length === 0" class="empty-tip">
            {{ $srv.getI18nByValue('暂无选择项') }}
          </div>
        </div>
      </Content>
    </Layout>
  </div>
</template>

<script lang="ts">
import { T_srv, Tsrv, ifs, ts, vue } from '@/services';


interface IChecker {
  value: string;
  label: string;
}

interface IOptionsData {
  id: string;
  checker?: IChecker;
  nodeID: string;
  label?: string;
  value?: string;
}

// 选项列表
interface IOptionsList {
  status: number;
  type: 0 | 2;
  nodeCode: string;
  id: string;
  data: IOptionsData;
  sn: number;
}

// 人员数据接口
interface IUser extends IOptionsList { selected?: boolean; }

interface IApprover {
  userID: string;
  userNO?: string;
  userName: string;
}

// 用户组数据接口
interface IUserGroup extends IOptionsList {
  approvers?: IApprover[];
  selected?: boolean;
}

// 已选择项接口
interface ISelectedItem extends IOptionsList {
  approvers?: IApprover[];
  selected?: boolean;
}

@T_srv.comp
export default class oUsersSelect extends vue {
  /* 父组件compBoxInfo */
  @T_srv.prop({
    required: false,
    type: Object,
    default: null
  })
  compBoxInfo: ifs.I_compBoxInfo;

  @T_srv.prop({
    required: false,
    type: Boolean,
    default: false
  })
  isShow: boolean;

  @T_srv.prop({
    required: false,
    type: Array<IOptionsList>,
    default: []
  })
  optionsList: Array<IOptionsList>;

  /* 组件名 */
  private name: string = 'oUsersSelect';

  private G_compName: string = this.name;

  /* 组件箱信息对象 */
  private GT_compBoxInfo: ifs.I_compBoxInfo;

  /* 组件箱对象 */
  private GT_compBox: ifs.I_compBox;

  /* 组件箱识别ID */
  private G_compID: string;

  // 人员数据
  private users: IUser[] = [];

  // 用户组数据
  private userGroups: IUserGroup[] = [];

  created() {
    // 如果父组件没有传参，那就产生一个
    this.GT_compBoxInfo = Tsrv.getCompInfo(this.compBoxInfo);
    this.G_compID = this.GT_compBoxInfo.compID;
    this.GT_compBox = this.GT_compBoxInfo.TcompBox;
    this.init();
  }

  mounted() {
    /* 向父组件发送实例 */
    this.GT_compBox.addCompMergeName(this.G_compID, this.G_compName, this);
    this.$emit('compBoxInfo', this.GT_compBoxInfo);
  }

  private init() {
    if (Tsrv.noValue(this.optionsList)) return;
    this.users = [];
    this.userGroups = [];
    this.optionsList.forEach(item => {
      if (item.type === 0){
        this.users.push({
          ...item,
          selected: false
        });
      } else if (item.type === 2) {
        this.userGroups.push({
          ...item,
          selected: false,
          approvers: []
        })
      }
    })
  }

    /**
   * 获取所选用户组成员
   */
  private getGroupDescription(group: IUserGroup): string {
    if (Tsrv.noValue(group.approvers)) return '';
    return group.approvers.map(approver => approver.userName).join('、');
  }

  /**
   * 获取已选择的用户
   */
  public getSelectedUsers(): ISelectedItem[] {
    return this.selectedItems.map(item => {
      delete item.selected;
      if (item.type === 2 && Tsrv.noValue(item.approvers)){
        delete item.approvers;
      }
      return item;
    });
  }

  /**
   * 处理用户组管理
   */
  private handleGroupManage(group: IUserGroup): void {
    const f = new ts.T_filter()
    f.filter = {
        _sys_user_group_id: {
          $in: [group.data.value]
        }
      }
    const filter = {
      initSearch: f
    };

    const config = {
      isFunLayout: false
    };
    Tsrv.utils
      .createModal('oMagicBox', {
        source: {
          funid: null,
          isRule: true,
          field: Tsrv.globalVar.tableName.SYS_USER_GROUP_DET,
          limit: 999,
          filter
        },
        config
      })
      .then(selectedData => {
        if (Tsrv.noValue(selectedData)) return;
        group.approvers = selectedData.map(it => {
          return {
            userID: it._sys_user_id,
            userName: it['m2o|_sys_user_id|_sys_user|user_name'],
            userNO: it.user_no
          }
        });
        group.selected = true;
        this.toggleGroupSelection(group, true);
      });
  }

  /**
   * 切换人员选择状态
   */
  private toggleUserSelection(user: IUser, checked?: boolean): void {
    const newSelected = checked !== undefined ? checked : !user.selected;
    // 使用Vue.set确保响应式更新
    this.$set(user, 'selected', newSelected);
  }

  /**
   * 切换用户组选择状态
   */
  private toggleGroupSelection(group: IUserGroup, checked?: boolean): void {
    const newSelected = checked !== undefined ? checked : !group.selected;
    if (newSelected && Tsrv.noValue(group.approvers)) {
      this.handleGroupManage(group);
    } else {
      // 使用Vue.set确保响应式更新
      this.$set(group, 'selected', newSelected);
    }
  }

  /**
   * 计算已选择项
   */
  get selectedItems(): ISelectedItem[] {
    const items: ISelectedItem[] = [];

    // 添加已选择的人员
    this.users.forEach(user => {
      if (user.selected) {
        items.push(user);
      }
    });

    // 添加已选择的用户组
    this.userGroups.forEach(group => {
      if (group.selected) {
        items.push(group);
      }
    });

    return items;
  }

  destroyed() {
    /* 注册组件销毁 */
    this.GT_compBox.removeCompMergeName(this.G_compID, this.G_compName);

    /* 如果父组件传入的compBoxInfo则删除本文件产生的引用,反之是本组件产生的ID统一删除 */
    if (Tsrv.utils.isEmpty(this.compBoxInfo)) {
      this.GT_compBox.removeCompsWithCompID(this.G_compID);
    } else {
      this.GT_compBox.removeCompsMergeName(this.G_compID, [
        `'${this.G_compName}'`
      ]);
    }
  }
}
</script>

<style lang="scss" scoped>
.users-select-container {
  height: 100%;
  width: 100%;

  .users-select-layout {
    height: 100%;
    background: #fff;

    .top-section {
      padding: 12px;
      overflow: hidden;

      .top-row {
        height: 100%;

        .list-col {
          height: 100%;
          display: flex;
          flex-direction: column;

          .list-header {
            margin-bottom: 8px;

            h3 {
              margin: 0;
              font-size: 14px;
              color: #515a6e;
              font-weight: 500;
            }
          }

          .user-list-content {
            flex: 1;
            overflow-y: auto;
            padding-right: 8px;
            display: grid;
            grid-template-columns: repeat(2, 1fr);
            gap: 8px;

            .user-card {
              margin-bottom: 0;
              cursor: pointer;
              transition: all 0.3s ease;
              border: 1px solid #dcdee2;
              position: relative;
              padding: 8px;
              max-height: 95px;

              &:hover {
                border-color: #2d8eff;
                box-shadow: 0 1px 4px rgba(45, 142, 255, 0.1);
              }

              &.selected {
                border-color: #2d8eff;
                background-color: rgba(45, 142, 255, 0.05);
              }

              .card-checkbox-top {
                position: absolute;
                top: 4px;
                right: 4px;
                z-index: 1;
              }

              .card-content {
                padding: 4px 0;

                .card-info {
                  .card-name {
                    font-weight: 500;
                    color: #17233d;
                    font-size: 13px;
                    margin-bottom: 2px;
                  }

                  .card-userNo {
                    font-size: 11px;
                    color: #808695;
                  }
                }
              }
            }
          }

          .group-list-content {
            flex: 1;
            overflow-y: auto;
            padding-right: 8px;

            .group-card {
              margin-bottom: 8px;
              cursor: pointer;
              transition: all 0.3s ease;
              border: 1px solid #dcdee2;
              position: relative;
              padding: 8px;

              &:hover {
                border-color: #2d8eff;
                box-shadow: 0 1px 4px rgba(45, 142, 255, 0.1);
              }

              &.selected {
                border-color: #2d8eff;
                background-color: rgba(45, 142, 255, 0.05);
              }

              .card-checkbox-top {
                position: absolute;
                top: 4px;
                right: 4px;
                z-index: 1;
              }

              .card-content {
                padding: 4px 0;
                margin-right: 60px;

                .card-info {
                  .card-name {
                    font-weight: 500;
                    color: #17233d;
                    font-size: 13px;
                    margin-bottom: 4px;
                  }

                  .card-details {
                    .card-description {
                      font-size: 11px;
                      color: #808695;
                      margin-bottom: 2px;
                      line-height: 1.3;
                    }
                  }
                }
              }

              .card-actions-bottom {
                position: absolute;
                bottom: 8px;
                right: 8px;

                button {
                  min-width: 50px;
                  height: 24px;
                  font-size: 11px;
                }
              }
            }
          }
        }
      }
    }

    .bottom-section {
      padding: 12px;
      overflow: hidden;

      .selected-header {
        margin-bottom: 8px;

        h3 {
          margin: 0;
          font-size: 14px;
          color: #515a6e;
          font-weight: 500;
        }
      }

      .selected-content {
        height: calc(100% - 32px);
        overflow-y: auto;
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
        gap: 8px;

        .selected-card {
          background: #f8f8f9;
          border: 1px solid #e8eaec;
          border-radius: 4px;
          padding: 8px;
          display: flex;
          justify-content: space-between;
          align-items: center;
          transition: all 0.3s ease;

          &:hover {
            border-color: #2d8eff;
            box-shadow: 0 1px 4px rgba(45, 142, 255, 0.1);
          }

          .selected-info {
            .selected-name {
              font-weight: 500;
              color: #17233d;
              font-size: 12px;
              margin-bottom: 2px;
            }

            .selected-type {
              font-size: 11px;
            }
          }
        }

        .empty-tip {
          grid-column: 1 / -1;
          text-align: center;
          color: #c5c8ce;
          padding: 20px 0;
          font-size: 12px;
        }
      }
    }
  }
}

// 响应式设计
@media (max-width: 1200px) {
  .users-select-container {
    .users-select-layout {
      .top-section {
        .top-row {
          flex-direction: column;

          .list-col {
            width: 100%;
            margin-bottom: 12px;

            .user-list-content {
              grid-template-columns: 1fr;
            }
          }
        }
      }
    }
  }
}

// 滚动条样式
::-webkit-scrollbar {
  width: 4px;
}

::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 2px;
}

::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 2px;
}

::-webkit-scrollbar-thumb:hover {
  background: #a8a8a8;
}
</style>
